package com.fc.test.util;

import cn.hutool.core.lang.Pair;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fc.test.common.domain.BaseObject;
import com.fc.test.common.schema.Column;
import com.fc.test.compiler.baseutil.smc.compiler.JavaStringCompiler;
import com.fc.test.compiler.baseutil.smc.compiler.MemoryClassLoader;
import com.fc.test.model.custom.TsysTables;
import com.google.gson.Gson;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.tuple.Triple;

/**
 * Created by Liaopan on 2019/7/3.
 */
public class ClassUtil {

    private static final Gson GSON = new Gson();

    private static final Map<String, Class> CLASS_CACHE = new ConcurrentHashMap<>();

    public static Object forNameAndFromJson(String tableName, List<Column> columnList,
                                            String jsonData) throws IOException, ClassNotFoundException {
        Class<?> aClass = forName(tableName, columnList);
        return GSON.fromJson(jsonData, forName(tableName, columnList));
    }

    public static Class<?> forName(String tableName, List<Column> columnList) throws IOException,
            ClassNotFoundException {
        StringBuilder sb = new StringBuilder(tableName.toLowerCase());
        Optional.ofNullable(columnList).ifPresent(list ->
                sb.append(";").append(list.stream()
                        .map(c -> StringUtils.lowerCase(c.getName())).collect(Collectors.joining(";"))));
        Class clazz = CLASS_CACHE.get(sb.toString());
        if(clazz != null) {
            return clazz;
        }
        final Triple<String, String, String> triple = GenUtils.generatorCode(tableName, columnList);
        final String clsName = triple.getMiddle();
        ClassLoader classLoader = ClassUtils.class.getClassLoader();
        JavaStringCompiler compiler = new JavaStringCompiler(classLoader);
        Map<String, byte[]> compile = compiler.compile(clsName + ".java", triple.getRight());
        MemoryClassLoader memoryClassLoader = new MemoryClassLoader(classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader);
        memoryClassLoader.addClassBytes(compile);
        clazz = memoryClassLoader.loadClass(triple.getLeft() + "." + clsName);
        CLASS_CACHE.putIfAbsent(sb.toString(),clazz);
        return clazz;
    }

    public static void main(String[] args)
            throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        TsysTables table = new TsysTables("OGG_TEST", "MEMORY", "Ogg 测试表 table", new Date());
        List<Map<String, String>> columns = new ArrayList<>();
        Map<String, String> idColumn = new HashMap<>();
        columns.add(idColumn);
        idColumn.put("columnName", "id");
        idColumn.put("dataType", "bigint");
        idColumn.put("columnComment", "主键");
        idColumn.put("extra", "");
        idColumn.put("columnKey", "PRI");
        String json = "{\"id\":123}";
        //BaseObject object = (BaseObject) ClassUtil.forName("OOG_TEST",columns,json);

        //System.out.println(object);


    }

}
